﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using System.Text;
using DO.Workflows;
using Microsoft.Office.Interop.Outlook;
using Attachment=System.Net.Mail.Attachment;
using Exception=System.Exception;

namespace BLL.Workflows
{
    public class EmailWorker:WorkerBase
    {
        #region Overrides of WorkerBase

        private EmailInstruction _Instruction;
        /// <summary>
        /// allow instruction to be changed at runtime
        /// </summary>
        public override InstructionBase Instruction
        {
            get
            {
                return _Instruction;
            }
            set
            {
                _Instruction = (EmailInstruction) value;
            }
        }

        private EmailOutput _Output;
        /// <summary>
        /// output
        /// </summary>
        public override ResultBase Output
        {
            get
            {
                return _Output;
            }
        }

        /// <summary>
        /// allow worker to be created based on component type
        /// </summary>
        public override Type ComponentType
        {
            get
            {
                return typeof (EmailComponent);
            }
        }

        /// <summary>
        /// allow instruction to be instantiated
        /// </summary>
        public override Type InstructionType
        {
            get
            {
                return typeof (EmailInstruction);
            }
        }

        public override event WorkerFinished WorkerFinishedEvent;
        public override event WorkerHasError WorkerErredEvent;
        public override event WorkerStatusChanged WorkerStatusChangedEvent;
        protected override void StartWork()
        {
            try
            {
                if(this._Instruction.UseOutlook)
                    this.SendEmailViaOutlook();
                else 
                    this.SendEmailUsingSmtp();

                this._Output = new EmailOutput();
                if (this.WorkerFinishedEvent != null)
                    this.WorkerFinishedEvent(this.JobTicket, this.GetType(), this.Instruction, this.Output);
            }
            catch (Exception ex)
            {
                if (this.WorkerErredEvent != null)
                    this.WorkerErredEvent(this.JobTicket, this.GetType(), this.Instruction, ex.Message, true);
            }
        }

        #endregion

        #region outlook
        private void SendEmailViaOutlook()
        {

            Application olApp = new Application();
            // Get the NameSpace and Logon information.
            NameSpace olNamespace = olApp.GetNamespace("mapi");

            // Log on by using a dialog box to choose the profile.
            olNamespace.Logon(Missing.Value, Missing.Value, true, true);

            MailItem mailItem = (MailItem)olApp.CreateItem(OlItemType.olMailItem);
            mailItem.BodyFormat = OlBodyFormat.olFormatHTML;
            // attachments 
            if (this._Instruction.Attachments != null)
            {
                foreach (string filePath in this._Instruction.Attachments)
                {
                    string fileName = Path.GetFileName(filePath);
                    mailItem.Attachments.Add(filePath, null, null, fileName);
                }
            }
            mailItem.Display(false);
            mailItem.Importance = OlImportance.olImportanceNormal;
            if (this._Instruction.Priority == MailPriority.High)
            {
                mailItem.Importance = OlImportance.olImportanceHigh;
            }
            else if (this._Instruction.Priority == MailPriority.Low)
            {
                mailItem.Importance = OlImportance.olImportanceLow;
            }
            mailItem.Subject = this._Instruction.Subject;
            string body = this._Instruction.Body;
            if (this._Instruction.BodyPlaceHolders != null && this._Instruction.BodyPlaceHolders.Count > 0)
            {
                foreach (string name in this._Instruction.BodyPlaceHolders.Keys)
                {
                    string val = this._Instruction.BodyPlaceHolders[name] ?? string.Empty;
                    body = body.Replace("@[" + name + "]", val);
                    body = body.Replace("${" + name + "}", val);
                }
            }
            mailItem.HTMLBody = body;
            string[] toAddresses = this._Instruction.ToAddress.Split(new char[] { ',', ';' });
            foreach (string toAddr in toAddresses)
            {
                mailItem.Recipients.Add(toAddr);
            }
            if (!string.IsNullOrEmpty(this._Instruction.CC))
            {
                string[] ccAddresses = this._Instruction.CC.Split(new char[] { ',', ';' });
                foreach (string ccAddr in ccAddresses)
                {
                    mailItem.CC.Insert(0, ccAddr);
                }
            }
            // mailItem.To = StringUtil.ToString(this._Instruction.To, ";");
            if (this._Instruction.Attachments != null && this._Instruction.Attachments.Count > 0)
            {
                int pos = 0;
                foreach (string filePath in this._Instruction.Attachments)
                {
                    if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
                    {
                        string attachmentError = string.Format("Attachment file is not found");
                        if (this.WorkerErredEvent != null)
                        {
                            this.WorkerErredEvent(this.JobTicket, this.GetType(), this._Instruction,
                                                  attachmentError, false);
                        }
                    }
                    else
                    {
                        pos++;
                        mailItem.Attachments.Add(filePath, OlAttachmentType.olByValue, pos, Path.GetFileName(filePath));
                    }
                }
            }
            mailItem.Send();
        }
        #endregion

        #region smtp
        private void SendEmailUsingSmtp()
        {
            MailMessage message = new MailMessage();
            message.From = new MailAddress(this._Instruction.FromAddress);
            string[] toAddresses = this._Instruction.ToAddress.Split(new char[] {',', ';'});
            foreach (string toAddr in toAddresses)
            {
                message.To.Add(new MailAddress(toAddr));
            }
            if (!string.IsNullOrEmpty(this._Instruction.CC))
            {
                string[] ccAddresses = this._Instruction.CC.Split(new char[] {',', ';'});
                foreach (string ccAddr in ccAddresses)
                {
                    message.CC.Add(new MailAddress(ccAddr));
                }
            }
            message.Subject = this._Instruction.Subject;
            string body = this._Instruction.Body;
            if (this._Instruction.BodyPlaceHolders != null && this._Instruction.BodyPlaceHolders.Count > 0)
            {
                foreach (string name in this._Instruction.BodyPlaceHolders.Keys)
                {
                    string val = this._Instruction.BodyPlaceHolders[name];
                    if (val == null)
                        val = string.Empty;
                    body = body.Replace("@[" + name + "]", val);
                    body = body.Replace("${" + name + "}", val);
                }
            }
            message.Body = body;
            message.Priority = this._Instruction.Priority;
            message.IsBodyHtml = true;
            SmtpClient smtp = new SmtpClient(this._Instruction.SmtpServer);
            if (this._Instruction.RequireAuthentication)
            {
                smtp.Credentials = new NetworkCredential(this._Instruction.UserName, this._Instruction.Password);
            }
            if (this.WorkerStatusChangedEvent != null)
            {
                this.WorkerStatusChangedEvent(this.JobTicket, this.GetType(), this._Instruction, this.WorkflowName,
                                              this.ComponentName,
                                              "Sending email message...", 15);
            }
            if (this._Instruction.EnableSSL)
            {
                smtp.EnableSsl = true;
            }

            // attachment 
            if (this._Instruction.Attachments != null && this._Instruction.Attachments.Count > 0)
            {
                foreach (string filePath in this._Instruction.Attachments)
                {
                    if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
                    {
                        string attachmentError = string.Format("Attachment file is not found");
                        if (this.WorkerErredEvent != null)
                        {
                            this.WorkerErredEvent(this.JobTicket, this.GetType(), this._Instruction,
                                                  attachmentError, false);
                        }
                    }
                    else
                    {
                        message.Attachments.Add(new Attachment(filePath));
                    }
                }
            }
            smtp.Send(message);
        }

        #endregion
    }
}
